<?php
// 应用公共文件
use app\common\model\finance\{TransactionRecord, TransactionRecordOther};
use app\common\service\ConfigService;
use app\common\service\FileService;
use payment\SlashService;
use payment\WorldFirstService;
use PHPMailer\PHPMailer\PHPMailer;
use think\helper\Str;
use app\common\model\user\User;
use app\common\model\card\{Card, CardBin};

/**
 * @notes 生成密码加密密钥
 * @param string $plaintext
 * @param string $salt
 * @return string
 * @author 段誉
 * @date 2021/12/28 18:24
 */
function create_password(string $plaintext, string $salt): string
{
    return md5($salt . md5($plaintext . $salt));
}


/**
 * @notes 随机生成token值
 * @param string $extra
 * @return string
 * @author 段誉
 * @date 2021/12/28 18:24
 */
function create_token(string $extra = ''): string
{
    $salt = env('project.unique_identification', 'likeadmin');
    $encryptSalt = md5($salt . uniqid());
    return md5($salt . $extra . time() . $encryptSalt);
}


/**
 * @notes 截取某字符字符串
 * @param $str
 * @param string $symbol
 * @return string
 * @author 段誉
 * @date 2021/12/28 18:24
 */
function substr_symbol_behind($str, $symbol = '.'): string
{
    $result = strripos($str, $symbol);
    if ($result === false) {
        return $str;
    }
    return substr($str, $result + 1);
}


/**
 * @notes 对比php版本
 * @param string $version
 * @return bool
 * @author 段誉
 * @date 2021/12/28 18:27
 */
function compare_php(string $version): bool
{
    return version_compare(PHP_VERSION, $version) >= 0 ? true : false;
}


/**
 * @notes 检查文件是否可写
 * @param string $dir
 * @return bool
 * @author 段誉
 * @date 2021/12/28 18:27
 */
function check_dir_write(string $dir = ''): bool
{
    $route = root_path() . '/' . $dir;
    return is_writable($route);
}


/**
 * 多级线性结构排序
 * 转换前：
 * [{"id":1,"pid":0,"name":"a"},{"id":2,"pid":0,"name":"b"},{"id":3,"pid":1,"name":"c"},
 * {"id":4,"pid":2,"name":"d"},{"id":5,"pid":4,"name":"e"},{"id":6,"pid":5,"name":"f"},
 * {"id":7,"pid":3,"name":"g"}]
 * 转换后：
 * [{"id":1,"pid":0,"name":"a","level":1},{"id":3,"pid":1,"name":"c","level":2},{"id":7,"pid":3,"name":"g","level":3},
 * {"id":2,"pid":0,"name":"b","level":1},{"id":4,"pid":2,"name":"d","level":2},{"id":5,"pid":4,"name":"e","level":3},
 * {"id":6,"pid":5,"name":"f","level":4}]
 * @param array $data 线性结构数组
 * @param string $symbol 名称前面加符号
 * @param string $name 名称
 * @param string $id_name 数组id名
 * @param string $parent_id_name 数组祖先id名
 * @param int $level 此值请勿给参数
 * @param int $parent_id 此值请勿给参数
 * @return array
 */
function linear_to_tree($data, $sub_key_name = 'sub', $id_name = 'id', $parent_id_name = 'pid', $parent_id = 0)
{
    $tree = [];
    foreach ($data as $row) {
        if ($row[$parent_id_name] == $parent_id) {
            $temp = $row;
            $child = linear_to_tree($data, $sub_key_name, $id_name, $parent_id_name, $row[$id_name]);
            if ($child) {
                $temp[$sub_key_name] = $child;
            }
            $tree[] = $temp;
        }
    }
    return $tree;
}


/**
 * @notes 删除目标目录
 * @param $path
 * @param $delDir
 * @return bool|void
 * @author 段誉
 * @date 2022/4/8 16:30
 */
function del_target_dir($path, $delDir)
{
    //没找到，不处理
    if (!file_exists($path)) {
        return false;
    }

    //打开目录句柄
    $handle = opendir($path);
    if ($handle) {
        while (false !== ($item = readdir($handle))) {
            if ($item != "." && $item != "..") {
                if (is_dir("$path/$item")) {
                    del_target_dir("$path/$item", $delDir);
                } else {
                    unlink("$path/$item");
                }
            }
        }
        closedir($handle);
        if ($delDir) {
            return rmdir($path);
        }
    } else {
        if (file_exists($path)) {
            return unlink($path);
        }
        return false;
    }
}


/**
 * @notes 下载文件
 * @param $url
 * @param $saveDir
 * @param $fileName
 * @return string
 * @author 段誉
 * @date 2022/9/16 9:53
 */
function download_file($url, $saveDir, $fileName)
{
    if (!file_exists($saveDir)) {
        mkdir($saveDir, 0775, true);
    }
    $fileSrc = $saveDir . $fileName;
    file_exists($fileSrc) && unlink($fileSrc);
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
    $file = curl_exec($ch);
    curl_close($ch);
    $resource = fopen($fileSrc, 'a');
    fwrite($resource, $file);
    fclose($resource);
    if (filesize($fileSrc) == 0) {
        unlink($fileSrc);
        return '';
    }
    return $fileSrc;
}


/**
 * @notes 去除内容图片域名
 * @param $content
 * @return array|string|string[]
 * @author 段誉
 * @date 2022/9/26 10:43
 */
function clear_file_domain($content)
{
    $fileUrl = FileService::getFileUrl();
    $pattern = '/<img[^>]*\bsrc=["\']' . preg_quote($fileUrl, '/') . '([^"\']+)["\']/i';
    return preg_replace($pattern, '<img src="$1"', $content);
}

/**
 * @notes 设置内容图片域名
 * @param $content
 * @return array|string|string[]|null
 * @author 段誉
 * @date 2024/2/5 16:36
 */
function get_file_domain($content)
{
    $fileUrl = FileService::getFileUrl();
    $imgPreg = '/(<img .*?src=")(?!https?:\/\/)([^"]*)(".*?>)/is';
    $videoPreg = '/(<video .*?src=")(?!https?:\/\/)([^"]*)(".*?>)/is';
    $content = preg_replace($imgPreg, "\${1}$fileUrl\${2}\${3}", $content);
    $content = preg_replace($videoPreg, "\${1}$fileUrl\${2}\${3}", $content);
    return $content;
}

/**
 * @notes uri小写
 * @param $data
 * @return array|string[]
 * @author 段誉
 * @date 2022/7/19 14:50
 */
function lower_uri($data)
{
    if (!is_array($data)) {
        $data = [$data];
    }
    return array_map(function ($item) {
        return strtolower(Str::camel($item));
    }, $data);
}


/**
 * @notes 获取无前缀数据表名
 * @param $tableName
 * @return mixed|string
 * @author 段誉
 * @date 2022/12/12 15:23
 */
function get_no_prefix_table_name($tableName)
{
    $tablePrefix = config('database.connections.mysql.prefix');
    $prefixIndex = strpos($tableName, $tablePrefix);
    if ($prefixIndex !== 0 || $prefixIndex === false) {
        return $tableName;
    }
    $tableName = substr_replace($tableName, '', 0, strlen($tablePrefix));
    return trim($tableName);
}


/**
 * @notes 生成编码
 * @param $table
 * @param $field
 * @param string $prefix
 * @param int $randSuffixLength
 * @param array $pool
 * @return string
 * @author 段誉
 * @date 2023/2/23 11:35
 */
function generate_sn($table, $field, $prefix = '', $randSuffixLength = 4, $pool = []): string
{
    $suffix = '';
    for ($i = 0; $i < $randSuffixLength; $i++) {
        if (empty($pool)) {
            $suffix .= rand(0, 9);
        } else {
            $suffix .= $pool[array_rand($pool)];
        }
    }
    $sn = $prefix . date('YmdHis') . $suffix;
    if (app()->make($table)->where($field, $sn)->find()) {
        return generate_sn($table, $field, $prefix, $randSuffixLength, $pool);
    }
    return $sn;
}


/**
 * @notes 格式化金额
 * @param $float
 * @return int|mixed|string
 * @author 段誉
 * @date 2023/2/24 11:20
 */
function format_amount($float)
{
    if ($float == intval($float)) {
        return intval($float);
    } elseif ($float == sprintf('%.1f', $float)) {
        return sprintf('%.1f', $float);
    }
    return $float;
}

/**
 * @param $to
 * @param $subject
 * @param $body
 * @return bool
 * @throws \PHPMailer\PHPMailer\Exception
 */
function send_mail($to, $subject, $body)
{

    // 从配置文件读取邮件配置
    $config = ConfigService::get('email');

    $mail = new PHPMailer(true);
    $mail->SMTPDebug = 0;  // 生产环境设为0，调试时可设为2

    // 服务器设置
    $mail->isSMTP();
    $mail->Host = $config['host'];
    $mail->SMTPAuth = true;
    $mail->Username = $config['username'];
    $mail->Password = $config['password'];
    $mail->SMTPSecure = $config['encryption'] == 'ssl' ? PHPMailer::ENCRYPTION_SMTPS : PHPMailer::ENCRYPTION_STARTTLS;
    $mail->Port = $config['port'];
    $mail->CharSet = 'UTF-8';

    // 设置超时时间
    $mail->Timeout = $config['timeout'] ?? 10;

    // 禁用SSL证书验证（如果SSL连接有问题）
    $mail->SMTPOptions = [
        'ssl' => [
            'verify_peer' => false,
            'verify_peer_name' => false,
            'allow_self_signed' => true
        ]
    ];

    // 收发件人
    $mail->setFrom($config['username']);
    $mail->addAddress($to);

    // 邮件内容
    $mail->isHTML(true);
    $mail->Subject = $subject;
    $mail->Body = $body;
    return $mail->send();
}

function encrypt($data, $key = '')
{
    if ($key == '') $key = md5('cardadmin2025');
    $ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
    $iv = openssl_random_pseudo_bytes($ivlen);
    $ciphertext_raw = openssl_encrypt($data, $cipher, $key, $options = 0, $iv);
    $hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary = true);
    return base64_encode($iv . $hmac . $ciphertext_raw);
}

function decrypt($ciphertext, $key = '')
{

    if (!$ciphertext) {
        return json_encode([
            'card_no' => '',
            'cvv' => '',
            'expired_month' => '',
            'expired_year' => '',
        ]);
    }

    if ($key == '') $key = md5('cardadmin2025');
    $c = base64_decode($ciphertext);
    $ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
    $iv = substr($c, 0, $ivlen);
    $hmac = substr($c, $ivlen, $sha2len = 32);
    $ciphertext_raw = substr($c, $ivlen + $sha2len);
    $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options = 0, $iv);
    $calcmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary = true);
    if (hash_equals($hmac, $calcmac)) { // PHP 5.6+ timing attack safe comparison
        return $original_plaintext;
    }
}

function get_user_info($user_id)
{
    $user_info = User::find($user_id);
    if ($user_info['role_id'] > 3) {
        $user_info['leader'] = User::where('id', $user_info['pid'])->value('account');
    }
    return [
        'user_id' => $user_id,
        'account' => $user_info['account'],
        'role_id' => $user_info['role_id'],
        'leader' => $user_info['leader'] ?? ''
    ];
}


//空中云付交易记录
function airwallex_bill($data)
{
    $transaction_id = $data['transaction_id'];

    $condition = [
        'transaction_id' => $transaction_id,
    ];

    $transaction_date = new \DateTime($data['transaction_date']);
    $transaction_date = $transaction_date->format('Y-m-d H:i:s');

    $posted_date = new \DateTime($data['posted_date']);
    $posted_date = $posted_date->format('Y-m-d H:i:s');

    $card = Card::where('card_id', $data['card_id'])
        ->field('card_id,card_no,user_id,group_id')
        ->findOrEmpty();

    //只记录系统开卡的交易记录
    if ($card->isEmpty()) return;

    $row = [
        'status' => $data['status'],
        'transaction_amount' => abs($data['transaction_amount']),
        'transaction_date' => $transaction_date,
        'transaction_type' => $data['transaction_type'],
        'billing_amount' => abs($data['billing_amount']),
        'billing_currency' => $data['billing_currency'],
        'auth_code' => $data['auth_code'],
        'merchant_name' => $data['merchant']['name'],
        'card_id' => $data['card_id'],
        'card_bin' => $data['card_bin'] ?? 11,
        'masked_card_number' => $data['masked_card_number'],
        'posted_date' => $posted_date,
        'failure_reason' => $data['failure_reason'] ?? '',
        'user_id' => $card['user_id'] ?? 0,
        'group_id' => $card['group_id'] ?? 0,
        'transaction_currency' => $data['transaction_currency'],
        'alias' => $card['alias'] ?? '',
//        'service_fee' => 0,
//        'service_amount' => 0,
    ];

    /**
     * 交易状态status:
     * 用户下单后，支付进入 PENDING；
     * 支付成功变为 APPROVED；
     * 若支付失败则为 FAILED；
     * 如果支付成功但之后退款，则可能标记为 REVERSED；
     * 若过了清算周期且完成结算，变为 CLEARED；
     * 如果支付链接或验证码超时未使用，则为 EXPIRED。
     *
     * 交易类型transaction_type:AUTHORIZATION,CLEARING,REFUND,REVERSAL,ORIGINAL_CREDIT
     */

//    if ($data['transaction_type'] == 'CLEARING') {
//        //计算服务费,此处可能包含小额服务费
//        if (isset($card['group_id'])) {
//            $serviceFee = CardBin::where(['group_id' => $card['group_id'], 'bin_id' => $card['card_bin']])->value('service_fee');
//
//            if ($serviceFee) {
//                $row['service_fee'] = $serviceFee;
//                $row['service_amount'] = abs($data['billing_amount']) * $serviceFee;
//            }
//        }
//    }


    try {
        $transaction = TransactionRecord::where($condition)->findOrEmpty();
        if (!$transaction->isEmpty()) {
            $result = $transaction->save($row);
            if (!$result) {
                throw new \Exception('更新交易记录失败');
            }
        } else {
            $newTransaction = TransactionRecord::create(array_merge($condition, $row));
            if (!$newTransaction) {
                throw new \Exception('创建交易记录失败');
            }
        }
    } catch (\Exception $e) {
        trace($e->getMessage(), 'error');
    }

}


//万里付卡交易记录
function worldfirst_bill($data)
{
    // Minor Unit = 0 的币种
    $minorUnit0 = ['JPY', 'KRW', 'VND'];
    // Minor Unit = 3 的币种
    $minorUnit3 = ['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND'];

    if (isset($data['assetId'])) {
        $cardId = $data['assetId'];
    } else {
        if (!isset($data['cardNickName'])) return;
        $cardId = Card::where('card_nick_name', $data['cardNickName'])
            ->where('card_no', 'like', '%' . substr($data['maskedCardNo'], -4))
            ->value('card_id');
    }
    $card = Card::where('card_id', $cardId)->findOrEmpty();

    $transactionRecord = new TransactionRecord();

    //非系统开卡的交易记录
    if ($card->isEmpty()) {
        $transactionRecord = new TransactionRecordOther();
    }

    //退款记录
    if ($data['billStatus'] == 'REFUNDED') {
        $transactionRecord = new TransactionRecordOther();
    }

//    交易金额
    //$transaction_amount = ($data['tradeAmount']['currency'] == 'USD') ? $data['tradeAmount']['value'] / 100 : $data['tradeAmount']['value'];
    // 交易金额
    $currency = $data['tradeAmount']['currency'];
    if (in_array($currency, $minorUnit0)) {
        $transaction_amount = $data['tradeAmount']['value'];
    } elseif (in_array($currency, $minorUnit3)) {
        $transaction_amount = $data['tradeAmount']['value'] / 1000;
    } else {
        $transaction_amount = $data['tradeAmount']['value'] / 100;
    }
//    账单金额
    $billing_amount = ($data['outAmount']['currency'] == 'USD') ? $data['outAmount']['value'] / 100 : $data['outAmount']['value'];

    $row = [
        'transaction_id' => $data['orderNo'],
        'card_id' => $cardId ?? '',
        'card_bin' => $data['card_bin'] ?? 10,
        'status' => $data['billStatus'],
        'transaction_type' => $data['billType'],
        'card_nickname' => $data['cardNickName'] ?? '',
        'masked_card_number' => $data['maskedCardNo'],
        'merchant_name' => $data['merchantName'],
        'transaction_amount' => abs($transaction_amount),
        'transaction_currency' => $data['tradeAmount']['currency'],
        'billing_amount' => abs($billing_amount),
        'billing_currency' => $data['outAmount']['currency'],
        'location_country' => $data['tradeCountry'] ?? '',
        'user_id' => $card['user_id'] ?? 0,
        'group_id' => $card['group_id'] ?? 0,
        'alias' => $card['alias'] ?? '',
//        'service_fee' => 0,
//        'service_amount' => 0,
    ];

    //注意别删:自定义的账单金额和币种，处理2025-7-30出现的欧元币种问题
    if (isset(config('billing_custom')[$data['orderNo']])) {
        $row['billing_currency'] = 'USD';
        $row['billing_amount'] = config('billing_custom')[$data['orderNo']];
    }

    if ($data['billStatus'] == 'SUCCESS') {
        //交易成功使用清算时间字段
        $transaction_date = new \DateTime($data['transactionTime']);
        $row['posted_date'] = $transaction_date->format('Y-m-d H:i:s');
    } else {
        //转换时间格式
        $transaction_date = new \DateTime($data['transactionTime']);
        $row['transaction_date'] = $transaction_date->format('Y-m-d H:i:s');
    }

    try {
        $condition = [
            'transaction_id' => $data['orderNo'],
        ];
        $transaction = $transactionRecord::where($condition)->findOrEmpty();

        if (!$transaction->isEmpty()) {
            $result = $transaction->save($row);
            if (!$result) {
                trace('更新交易记录失败');
                return false;
            }
        } else {
            $newTransaction = $transactionRecord::create($row);
            if (!$newTransaction) {
                trace('创建交易记录失败');
                return false;
            }
        }
    } catch (\Exception $e) {
        trace($e->getMessage(), 'error');
    }
    return true;

}


//slash交易记录
function slash_bill($data)
{
    //非卡片交易的不计算
    if (!isset($data['cardId'])) return;

    $transaction_id = $data['id'];

    $condition = [
        'transaction_id' => $transaction_id,
    ];

    $transaction_date = new \DateTime($data['date']);
    $transaction_date = $transaction_date->format('Y-m-d H:i:s');

    $posted_date = new \DateTime($data['authorizedAt']);
    $posted_date = $posted_date->format('Y-m-d H:i:s');

    $card = Card::where('card_id', $data['cardId'])
        ->field('card_id,card_no,user_id,group_id')
        ->findOrEmpty();

    $transactionRecord = new TransactionRecord();

    //非系统开卡的交易记录
    if ($card->isEmpty()) {
//        file_put_contents('slash_card_other.txt', $data['cardId'] . PHP_EOL, FILE_APPEND);
//        return;
        $transactionRecord = new TransactionRecordOther();
    }
    //退款记录
    if ($data['detailedStatus'] == 'refund') {
        $transactionRecord = new TransactionRecordOther();
    }

    if ($data['amountCents'] < 0) {
        $transaction_amount = 0 - ($data['originalCurrency']['amountCents'] ?? 0) / 100;
    } else {
        $transaction_amount = ($data['originalCurrency']['amountCents'] ?? 0) / 100;
    }
    $billing_amount = ($data['amountCents'] ?? 0) / 100;
    $row = [
        'status' => $data['status'],
        'transaction_amount' => abs($transaction_amount),
        'transaction_currency' => $data['originalCurrency']['code'] ?? '',
        'transaction_date' => $transaction_date,
        'transaction_type' => $data['detailedStatus'] ?? '',
        'billing_amount' => abs($billing_amount),
        'billing_currency' => 'USD',

        'merchant_name' => $data['description'] ?? '',
        'card_id' => $data['cardId'] ?? '',
        'card_bin' => $card['card_bin'] ?? 12,
        'masked_card_number' => $card['card_no'] ?? '',
        'posted_date' => $posted_date,
        'alias' => $card['alias'] ?? '',
        'user_id' => $card['user_id'] ?? 1,
        'group_id' => $card['group_id'] ?? 1,
//        'transaction_currency' => $data['transaction_currency'],
//        'service_fee' => 0,
//        'service_amount' => 0,
        'location_city' => $data['merchantData']['location']['city'] ?? '',
        'location_country' => $data['merchantData']['location']['country'] ?? '',
        'location_state' => $data['merchantData']['location']['state'] ?? '',
        'location_zip' => $data['merchantData']['location']['zip'] ?? '',
    ];

    try {
        $transaction = $transactionRecord::where($condition)->findOrEmpty();

        if ($transaction->isEmpty()) {
            $transactionRecord::create(array_merge($condition, $row));
        } else {
            // 检查是否是pending变为reversed的情况
            $isStatusChanged = $transaction->transaction_type == 'pending' && $row['transaction_type'] == 'reversed';
            // $update = $transaction->update($row);
            $update = $transactionRecord::where($condition)->update($row);
            // 只在状态从pending变为reversed时才写日志
            if ($update && $isStatusChanged) {
                file_put_contents('reversed.log', $transaction_id . "\t" . $row['billing_amount'] . "\n", FILE_APPEND);
            }
        }
    } catch (\Exception $e) {
        trace($e->getMessage(), 'error');
    }

}


/**
 * 获取支付验证码
 *
 * @param string $email_address 邮箱地址
 * @param string $password 邮箱密码
 * @param string $card_number 卡片尾号（4位数字），必须传入
 * @param string $imap_server IMAP服务器地址及端口，默认：mail.1000huiq.com:143
 * @return array|null 成功返回包含邮件主题、内容、验证码和卡片信息的数组，否则返回 null
 */


function get_verification_code($card_number)
{
    // 设置错误报告
    error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);

    try {
        $config = ConfigService::get('email');
        $imap_server = $config['imap_host'] ?? 'imap.gmail.com';
        $email_address = $config['username'];
        $password = $config['password'];

        // 连接到IMAP服务器
        file_put_contents('/dev/shm/imap.log', "正在连接IMAP服务器...\n");
        $mailbox = "{" . $imap_server . ":993/imap/ssl/novalidate-cert}INBOX";
        $imap = imap_open($mailbox, $email_address, $password, OP_READONLY);

        if (!$imap) {
            file_put_contents('/dev/shm/imap.log', "连接失败: " . imap_last_error() . "\n", FILE_APPEND);
            return false;
        }

        // 搜索最近7天的邮件
        $search_date = date('d-M-Y', strtotime('-2 hours'));
        $emails = imap_search($imap, "SINCE \"$search_date\"");

        if (!$emails) {
            // 如果最近2小时没有邮件，则搜索最近12小时
            $search_date = date('d-M-Y H:i:s', strtotime('-12 hours'));
            $emails = imap_search($imap, "SINCE \"$search_date\"");
        }

        if (!$emails) {
            file_put_contents('/dev/shm/imap.log', "搜索失败: " . imap_last_error() . "\n", FILE_APPEND);
            imap_close($imap);
            return false;
        }

        file_put_contents('/dev/shm/imap.log', "找到 " . count($emails) . " 封邮件\n", FILE_APPEND);
        rsort($emails);//倒序处理
        // 获取最新的20封邮件
        $emails = array_slice($emails, 0, 20);

        foreach ($emails as $email_id) {
            file_put_contents('/dev/shm/imap.log', "正在处理邮件 ID: $email_id\n", FILE_APPEND);
            // 获取邮件结构
            $structure = imap_fetchstructure($imap, $email_id);

            // 获取邮件主题
            $subject = '';
            $header = imap_headerinfo($imap, $email_id);
            if ($header && isset($header->subject)) {
                $subject = imap_utf8($header->subject);
            }

            // 获取邮件内容
            $content = '';

            if ($structure->type == 1) { // 多部分邮件
                $parts = $structure->parts;
                foreach ($parts as $part_number => $part) {
                    if ($part->type == 0 && $part->subtype == 'PLAIN') {
                        $message = imap_fetchbody($imap, $email_id, $part_number + 1);
                        if ($message) {
                            // 处理编码
                            if ($part->encoding == 3) { // BASE64
                                $message = base64_decode($message);
                            } elseif ($part->encoding == 4) { // QUOTED-PRINTABLE
                                $message = quoted_printable_decode($message);
                            }

                            // 处理字符集
                            if (isset($part->parameters)) {
                                foreach ($part->parameters as $param) {
                                    if (strtolower($param->attribute) == 'charset') {
                                        $charset = $param->value;
                                        if (strtolower($charset) != 'utf-8') {
                                            $message = iconv($charset, 'UTF-8//IGNORE', $message);
                                        }
                                        break;
                                    }
                                }
                            }
                            $content .= $message;
                        }
                    }
                }
            } else { // 单部分邮件
                $message = imap_body($imap, $email_id);
                if ($message) {
                    // 处理编码
                    if ($structure->encoding == 3) { // BASE64
                        $message = base64_decode($message);
                    } elseif ($structure->encoding == 4) { // QUOTED-PRINTABLE
                        $message = quoted_printable_decode($message);
                    }

                    // 处理字符集
                    if (isset($structure->parameters)) {
                        foreach ($structure->parameters as $param) {
                            if (strtolower($param->attribute) == 'charset') {
                                $charset = $param->value;
                                if (strtolower($charset) != 'utf-8') {
                                    $message = iconv($charset, 'UTF-8//IGNORE', $message);
                                }
                                break;
                            }
                        }
                    }
                    $content = $message;
                }
            }

            if (empty($content)) {
                continue;
            }

            // 搜索验证码
            $verification_patterns = [
                '/(?:验证码|支付验证码|您的验证码|验证号码)[^\d]*?(\d{6})(?![\d])/',
                '/[^\d](\d{6})[^\d](?:验证码|支付码|验证号码)/',
                '/(?:code|verification)[^\d]*?(\d{6})(?![\d])/i'
            ];

            $verification_code = null;
            foreach ($verification_patterns as $pattern) {
                if (preg_match($pattern, $content, $matches)) {
                    $verification_code = $matches[1];
                    file_put_contents('/dev/shm/imap.log', "验证码: $verification_code\n", FILE_APPEND);
                    break;
                }
            }

            if (!$verification_code) {
                continue;
            }

            // 搜索卡片尾号
            $card_patterns = [
                '/(?:卡片尾号|卡号尾数|卡末四位|尾号)[^\d]*?(\d{4})(?![\d])/',
                '/[^\d](\d{4})[^\d](?:卡号|尾号)/'
            ];

            $found_card_number = null;
            foreach ($card_patterns as $pattern) {
                if (preg_match($pattern, $content, $matches)) {
                    $found_card_number = $matches[1];
                    break;
                }
            }

            // 如果指定了卡片尾号，检查是否匹配
            if ($card_number) {
                if ($found_card_number && $found_card_number === $card_number) {
                    imap_close($imap);
                    return [
//                        'subject' => $subject,
//                        'content' => $content,
                        'code' => $verification_code,
                        'card_info' => "卡片尾号: $found_card_number"
                    ];
                }
            } else {
                // 如果没有指定卡号，只要找到验证码就返回
                imap_close($imap);
                return [
//                    'subject' => $subject,
//                    'content' => $content,
                    'code' => $verification_code,
                    'card_info' => $found_card_number ? "卡片尾号: $found_card_number" : null
                ];
            }
        }

        imap_close($imap);
        return false;

    } catch (Exception $e) {
        if (isset($imap) && is_resource($imap)) {
            imap_close($imap);
        }
        return false;
    }
}

//实时更新卡片额度
function update_card_detail($cardId)
{
    $card = Card::where('card_id', $cardId)->findOrEmpty();
    if ($card->isEmpty()) {
        return [];
    }
    $row = [];
    //万里付
    if ($card['card_bin'] == 10 || $card['card_bin'] == 13) {
        $wordFirstType = match ($card['card_bin']) {
            10 => 'worldfirst',
            13 => 'worldfirst_hk',
        };
        $worldFirst = new WorldFirstService($wordFirstType);
        $result = $worldFirst->getCardDetail($card['card_id']);
        if (isset($result['cardLimitDetail']['monthlyLimit'])) {
            $perCardLimit = $result['cardLimitDetail']['perCardLimit'] ?? $result['cardLimitDetail']['monthlyLimit'];
            $row = [
                'spend_money' => $perCardLimit['used']['value'] / 100,
                'limit_money' => $perCardLimit['range']['value'] / 100
            ];
            Card::where('card_id', $card['card_id'])->update($row);
        }
    }
    //slash
    if ($card['card_bin'] == 12 || $card['card_bin'] == 15) {
        $slashService = new SlashService($card['card_bin']);
        $result = $slashService->getCardUtilization($card['card_id']);
        if (isset($result['spend']['amountCents'])) {

            $available = $result['availableBalance']['amountCents'] ?? 0;
            $row = [
                'spend_money' => $result['spend']['amountCents'] / 100,
            ];
            if ($available) $row['limit_money'] = ($available + $result['spend']['amountCents']) / 100;
            Card::where('card_id', $card['card_id'])->update($row);
        }
    }
    return $row;
}